﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace FySystem.Net.SimSocket
{
    /// <summary>
    /// 将异步的发送和接收转换为同步的发送接收，await和async不太懂，不确定能否满足需求，这个类是为了解决以下问题：
    /// 网页调用后台api后，api需要向另一个程序B发送消息，并必须要等待B返回结果后才能继续
    /// </summary>
    public class SyncSender
    {
        private ManualResetEvent _allDone = new ManualResetEvent(false);

        private bool _isback = false;
        private byte[] _result = null;                  //远端返回的数据

        /// <summary>
        /// 发送数据，并接收远端回调，不支持针对同一个SimClient进行多线程同时调用，并且该函数会修改SimClient的OnReceive回调，
        /// 因此为了确保不会错乱，最好不要设置SimClient的OnReceive回调
        /// </summary>
        /// <param name="client"></param>
        /// <param name="data"></param>
        /// <param name="timeOut">超时时间，单位ms</param>
        /// <param name="isFinish"></param>
        /// <returns></returns>
        public byte[] Send(SimClient client, byte[] data, int timeOut = 15000, bool isFinish = true)
        {
            byte[] res = null;
            try
            {
                if (client == null)
                    throw new Exception("传入连接为空~");

                _allDone.Reset();
                client.OnReceive = ReceiveCallback;
                client.Send(data, isFinish);

                //线程阻塞，等待远端数据返回
                _allDone.WaitOne(timeOut);

                //判断是否超时
                if (_isback == false)
                    throw new Exception("请求超时~");

                res = _result;
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 回调
        /// </summary>
        /// <param name="client"></param>
        /// <param name="data"></param>
        /// <param name="isFinish"></param>
        private void ReceiveCallback(SimClient client, FrameInfo frame)
        {
            try
            {
                _result = frame.Frame;
                _isback = true;
                _allDone.Set();         //解除线程阻塞
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
